package com.junglone.gateway.admin.route;

import static java.util.Collections.synchronizedMap;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.junglone.gateway.admin.domain.MongoRoute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.junglone.gateway.admin.dao.MongoDao;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * Description: 
 * 
 * @author junglone: <a href="mailto:cjlnzb@hotmail.com">cjlnzb@hotmail.com</a>
 * @since 2021/04/03 16:32
 */
@Component
public class MongoRouteDefinitionRepository implements RouteDefinitionRepository {

	private static final Logger LOGGER = LoggerFactory.getLogger(MongoRouteDefinitionRepository.class);

	@Resource
	private MongoDao<MongoRoute> mongoRouteDao;

	@Override
	public Flux<RouteDefinition> getRouteDefinitions() {

		Criteria criteria = Criteria.where("currentStatus").is(1);
		Query query = new Query();
		query.addCriteria(criteria);

		List<MongoRoute> routeDefinitions = mongoRouteDao.findAll(query, MongoRoute.class);

		if (LOGGER.isInfoEnabled()) {

			routeDefinitions.forEach(route -> LOGGER.info("route ==== {}", route));
		}

		return Flux.fromIterable(routeDefinitions);
	}


	private final Map<String, RouteDefinition> routes = synchronizedMap(
			new LinkedHashMap<String, RouteDefinition>());

	@Override
	public Mono<Void> save(Mono<RouteDefinition> route) {
		return route.flatMap(r -> {

			LOGGER.info("++++++++++ before save ++++++++++ currentRoutes ==== {}", routes);

			if (StringUtils.isEmpty(r.getId())) {
				return Mono.error(new IllegalArgumentException("id may not be empty"));
			}
			routes.put(r.getId(), r);

			LOGGER.info("++++++++++ after save ++++++++++ currentRoutes ==== {}", routes);

			return Mono.empty();
		});
	}

	@Override
	public Mono<Void> delete(Mono<String> routeId) {
		return routeId.flatMap(id -> {
			if (routes.containsKey(id)) {
				routes.remove(id);
				return Mono.empty();
			}
			return Mono.defer(() -> Mono.error(
					new NotFoundException("RouteDefinition not found: " + routeId)));
		});
	}

}
